﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using COFE.Core.Lister;
using COFE.Core;
using COFE.Core.Utils;
using COFE.Core.Entry;

namespace COFE.Core.Actions
{
    public class EntryActionProvider : ISecondaryPropertyProvider<IEntryList>
    {
        #region Constructor

        #endregion

        #region Methods

        public object[] GetSupportedProperty(IEntryList sourceObj)
        {
            return new object[] {
                    EntryActions.Parse,
                    EntryActions.List,
                    EntryActions.Refresh,                    
                    EntryActions.Delete,
                    EntryActions.Rename,
                    EntryActions.CopyTo, 
                    EntryActions.CreateDirectory
                };
        }

        public bool IsPropertyReadOnly(IEntryList sourceObj, object property)
        {
            return true;
        }


        public PropertyPair GetProperty(IEntryList sourceObj, object property)
        {
            switch ((int)property)
            {
                case (int)EntryActions.Parse:
                    return new PropertyPair(property, (Func<IEntryList, string, IWorkProgress, IEntryList>)Parse);
                case (int)EntryActions.List:
                    return new PropertyPair(property, (Func<IEntryList, string, IWorkProgress, IEntryList>)List);

                case (int)EntryActions.Refresh:
                    return new PropertyPair(property, (Func<IEntryList, string, IWorkProgress, IEntryList>)Refresh);
                case (int)EntryActions.Delete:
                    return new PropertyPair(property, (Func<IEntryList, string, IWorkProgress, IEntryList>)Delete);
                case (int)EntryActions.Rename:
                    return new PropertyPair(property, (Func<IEntryList, string, IWorkProgress, IEntryList>)Rename);
                case (int)EntryActions.CopyTo:
                    return new PropertyPair(property, (Func<IEntryList, string, IWorkProgress, IEntryList>)CopyTo);
                case (int)EntryActions.CreateDirectory:
                    return new PropertyPair(property, (Func<IEntryList, string, IWorkProgress, IEntryList>)CreateDirectory);
            }

            throw new NotSupportedException(property.ToString());
        }

        public void SetProperty(IEntryList sourceObj, object property, object value)
        {
            throw new NotSupportedException(property.ToString());
        }

        IEntryList Parse(IEntryList input, string param, IWorkProgress progress)
        {
            var stringDic = StringUtils.ParamStringToDic(param);
            if (!stringDic.ContainsKey("path"))
                throw new ArgumentException("Path not specified.");
            IFileSystemInfo entry = COFEShared.CurrentUserProfile.TryParsePath(stringDic["path"]);
            if (entry == null)
                throw new System.IO.FileNotFoundException(stringDic["path"]);

            if (stringDic.ContainsKey("type"))
            {
                bool match = false;
                switch (stringDic["type"])
                {
                    case "file": match = entry is IFileInfo; break;
                    case "directory": match = entry is IDirectoryInfo; break;
                }
                if (!match)
                    throw new Exception("Type unknown or not match.");
            }

            return new OneEntryList(entry);
        }

        IEntryList List(IEntryList input, string param, IWorkProgress progress)
        {
            IAutoEntryList retVal = null;

            var stringDic = StringUtils.ParamStringToDic(param);
            string filter = "";

            if (stringDic.ContainsKey("filter"))
                filter = stringDic["filter"];

            retVal = new AutoEntryList(Guid.NewGuid(), "", 
                (from f in input.Entries where f is IDirectoryInfo
                select f as IDirectoryInfo).ToArray(),
                filter);


            var etor = retVal.Entries.GetEnumerator();

            var counter = 0;
            while (progress.ReportProgress(-1, counter++) && etor.MoveNext())
            {
                progress.CheckPause();
                //Do nothing.
            }

            if (retVal.Error != null)
                throw new Exception(retVal.Error.Message, retVal.Error);

            return retVal;



        }


        IEntryList Refresh(IEntryList input, string param, IWorkProgress progress)
        {
            int count = 0;
            int total = input is ICustomEntryList ? input.Entries.Count() : -1;
            progress.ReportProgress(total, count);
            foreach (var e in input.Entries)
            {
                progress.CheckPause();
                e.Refresh();
                progress.ReportProgress(total, ++count);
            }

            return input;
        }

        IEntryList Delete(IEntryList input, string param, IWorkProgress progress)
        {
            int count = 0;
            int total = input is ICustomEntryList ? input.Entries.Count() : -1;
            progress.ReportProgress(total, count);
            foreach (var e in input.Entries)
            {
                progress.CheckPause();
                e.Delete();
                progress.ReportProgress(total, ++count);
            }

            return NullEntryList.Create();
        }

        IEntryList Rename(IEntryList input, string param, IWorkProgress progress)
        {
            var stringDic = StringUtils.ParamStringToDic(param);

            if (stringDic.ContainsKey("name"))
            {
                var firstEntry = input.Entries.First() as IInternalFileSystemInfoExA;
                var parent = firstEntry.Parent as IInternalDirectoryInfoExA;
                parent.DirectoryController.Rename(firstEntry, stringDic["name"]);

                string newPath = COFEPath.Combine(parent.ParseName, stringDic["name"]);
                var renamedEntry = COFEShared.CurrentUserProfile.TryParsePath(newPath);
                if (renamedEntry == null)
                    throw new Exception("Rename failed.");
                else return new OneEntryList(renamedEntry);
            }

            return new OneEntryList(input.Entries.First());
        }

        IEntryList CopyTo(IEntryList input, string param, IWorkProgress progress)
        {
            var stringDic = StringUtils.ParamStringToDic(param);
            if (!stringDic.ContainsKey("dest"))
                throw new ArgumentException("dest not specified.");
            var destDir = COFEShared.CurrentUserProfile.TryParsePath(stringDic["dest"]) as IInternalDirectoryInfoExA;
            if (destDir == null)
                if (stringDic.ContainsKey("create") && stringDic["create"].ToLower() == "true")
                    destDir = COFEShared.CurrentUserProfile.Directory.CreateDirectory(stringDic["dest"]) as IInternalDirectoryInfoExA;
                else
                    throw new ArgumentException("dest not a directory or not found.");

            var destDirEntryList = new OneEntryList(destDir);
            if (destDirEntryList.HasAction(InternalActions.Transfer))
            {
                //Use Transfer method.
                var TransferAction = destDirEntryList.GetAction(InternalActions.Transfer)
                    as Func<IEntryList, string, IWorkProgress, IEntryList>;
                return TransferAction(input, param, progress);
            }
            else
            {
                //Copy one by one.
                int count = 0;
                List<string> copiedFiles = new List<string>();

                foreach (var entry in input.Entries)
                {
                    destDir.DirectoryController.Copy(entry as IInternalFileSystemInfoExA, destDir, true);
                    if (!progress.ReportProgress(++count, -1, entry.Name))
                        return null;
                    progress.CheckPause();
                    copiedFiles.Add(entry.Name);
                }

                destDir.Refresh();
                var entryToReturn = from e in destDir.DirectoryLister.List(destDir, Profile.EntryConstructionFlags.Default)
                                    where copiedFiles.Contains(e.Name, StringComparer.InvariantCultureIgnoreCase)
                                    select e;
                var retEntryList = new CustomEntryList("");
                retEntryList.AddRange(entryToReturn);
                return retEntryList;
            }
        }

        IEntryList CreateDirectory(IEntryList input, string param, IWorkProgress progress)
        {
            var stringDic = StringUtils.ParamStringToDic(param);
            if (!stringDic.ContainsKey("path"))
                throw new ArgumentException("path not specified.");
            string destPath = stringDic["path"];
            string type = stringDic.ContainsKey("type") ? stringDic["type"] : null;
            IDirectoryInfo destDir;
            if (String.IsNullOrEmpty(type))
                destDir = COFEShared.CurrentUserProfile.Directory.CreateDirectory(destPath);
            else destDir = COFEShared.CurrentUserProfile.Directory.CreateVirtualDirectory(destPath, type);

            return new OneEntryList(destDir);
        }

        #endregion

        #region Data

        #endregion

        #region Public Properties

        #endregion
    }
}
